#include "tis.h"
#include <stdlib.h>


Tis::Tis(int nTisSeq, int nPidsSeq, QObject *parent) :
    QObject(parent)
{
    QByteArray bytes;
    QDataStream stream(&bytes, QIODevice::ReadWrite);
    stream << 0x02 << 0x45 << 0x31 << 0x31 << 0x03;
    this->CheckBCC(bytes);

    m_isTrunAround = false;
    lastStatus = 0;

    m_nTisSeq = nTisSeq;
    m_nPidsSeq = nPidsSeq;
    m_status = 0;
    m_statusID = 0;
    lastStationID = -1;
    m_com = new TisSerialPort(this);
    connect(m_com, SIGNAL(dataArrive(char*,qint64)), this, SLOT(recvFromTis(char*,qint64)));
}

Tis::~Tis()
{
   m_com->ClosePort();
   delete m_com;
}

bool Tis::OpenPort(int nPort, ulong dwBaudRate, QueryMode mode)
{
    bool isOpenSuccess;
    isOpenSuccess = m_com->OpenPort(nPort, dwBaudRate, mode);
    return isOpenSuccess;
}

bool Tis::OpenPort(/*const QString & name*/QString name, ulong dwBaudRate, QueryMode mode)
{
//    qDebug() << "openPort..............>>>" << name << dwBaudRate << mode;
    return m_com->OpenPort(name, dwBaudRate, mode);
}

void Tis::closePort()
{
    return m_com->ClosePort();
}

void Tis::setSeq(const int nTisSeq, const int nPidsSeq)
{
    m_nTisSeq = nTisSeq;
    m_nPidsSeq = nPidsSeq;
}

qint64 Tis::Send(tisAnswerPkg/*pisToTisPkg*/* data)
{
   char sz[6] = {0};
   memcpy(sz, (char*)data, 6);
   return m_com->Send((char*)data, sizeof(tisAnswerPkg)/*sizeof(data)*/);      //sizeof(data)==4;sizeof(tisAnswerPkg)==6
}

qint64 Tis::sendToTis(char ans)
{
    //回复TIS
    tisAnswerPkg answerPkg;
    memset((char*)&answerPkg, 0, sizeof(tisAnswerPkg));
    answerPkg.head.stx = 0x02;
    answerPkg.head.type = m_nPidsSeq;
    answerPkg.head.cmd = ans;
    answerPkg.tail.etx = 0x03;

    QByteArray check;
    unsigned char bcc[2] = {0};
    check.append((char*)&answerPkg, sizeof(tisAnswerPkg)-2);
    CreateBCC(check, bcc);

    answerPkg.tail.hbcc = bcc[1];
    answerPkg.tail.lbcc = bcc[0];

    return m_com->Send((char*)&answerPkg, sizeof(tisAnswerPkg)/*sizeof(data)*/);      //sizeof(data)==4;sizeof(tisAnswerPkg)==6
}

qint64 Tis::sendToTis(char type, char ans)
{
    //ANS Control commands(answerPkg.head.cmd)
    //30H Correct
    //31H BCC error
    //32H Length error
    //33H Format error
    //34H Display fault
    //回复TIS
    tisAnswerPkg answerPkg;
    memset((char*)&answerPkg, 0, sizeof(tisAnswerPkg));
    answerPkg.head.stx = 0x02;
    answerPkg.head.type = type;
    answerPkg.head.cmd = ans;
    answerPkg.tail.etx = 0x03;

    QByteArray check;
    unsigned char bcc[2] = {0};
    check.append((char*)&answerPkg, sizeof(tisAnswerPkg)-2);
    CreateBCC(check, bcc);

    answerPkg.tail.hbcc = bcc[1];
    answerPkg.tail.lbcc = bcc[0];

    return m_com->Send((char*)&answerPkg, sizeof(tisAnswerPkg)/*sizeof(data)*/);
}

void Tis::recvFromTis(char *data, qint64 len)
{
    if((data == NULL)||(len <= 0))
    {
       return;
    }

//    QString strLog;
//    strLog.append(data);
//    strLog.append("\n");
//    logger()->info(strLog);

    //缓冲
    m_buf.append(data, len);
    //分析协议
    AnalyzeData(m_buf);
   // AnalyzeData(&m_buf);
    //转发信息
}

//些函数太长，应该再细分功能
void Tis::AnalyzeData(QByteArray& buf)
{
    int i = 0;
    while ( i < buf.size())
    {
        if (buf.at(i) == 0x02)     //找到帧头
        {
            //!!!要判断buf长度
            if((buf.size()-i)>sizeof(tisHead))
            {
             // tisHead* head = (tisHead*)(&buf[i]);//&buf[i]这种表达有问题
                tisHead* head = (tisHead*)(buf.data()+i);

                switch(head->cmd)
                {
                case 0x30:
                {
                    if((buf.size()-i) >= sizeof(tisNormalPkg))
                    {
                      //tisNormalPkg* pkg= (tisNormalPkg*)(&buf[i]);//&buf[i]这种表达有问题
                        tisNormalPkg* pkg= (tisNormalPkg*)(buf.data()+i);
                        if(pkg->tail.etx == 0x03)//完整的一帧
                        {
                            if(pkg->head.type == m_nTisSeq)
                            {
                                QByteArray bufCheck;
                                bufCheck.append((char*)pkg, sizeof(tisNormalPkg));
                                if(CheckBCC(bufCheck))
                                {
                                    tisToPisPkg msgPkg;
                                    // msgPkg.status = TranslateStatus(pkg->data.status)/*pkg->data.status*/;           //这个要进一步处理，不能直接赋值

                                    bool bChange = TranslateStatus(pkg->data.status, msgPkg.status, msgPkg.platSide)/*pkg->data.status*/;

//                                    qDebug() << "lastStationID=============>" << lastStationID << " pkg->data.stationID" <<  pkg->data.stationID;

                                    msgPkg.routeID = pkg->data.routeID;
                                    msgPkg.stationID = pkg->data.stationID;
                                    msgPkg.destID = pkg->data.destID;
//                                    if (!m_isTrunAround && (lastStationID == 0 && pkg->data.stationID != 0))
                                    if ((lastStationID == 0 && pkg->data.stationID != 0))
                                    {
                                        msgPkg.status = STATUS_REST;
                                        bChange = true;
                                    } else if (pkg->data.stationID == 0  || (lastStatus == STATUS_CABUNOCCUPIED))
                                    {
                                        msgPkg.status = STATUS_CABOCCUPIED;
//                                        msgPkg.stationID = stationID;
//                                        msgPkg.routeID = lastRoutID - 1;
//                                        qDebug() << ".............STATUS_CABOCCUPIEDSTATUS_CABOCCUPIED...........................>";
                                    }

//                                    int stationID = lastStationID;
                                    lastStationID = pkg->data.stationID;

                                    lastStatus = msgPkg.status;
                                    lastRoutID = msgPkg.routeID;

                                    if (g_stDebugConfig.isDebugTisCtl)
                                    {
                                        QStringList list1;
                                        list1 << "STATUS_CABOCCUPIED" << "STATUS_REST" << "STATUS_DOOROPEN" << "STATUS_DOORCLOSE" << "STATUS_TRAVELING" \
                                              << "STATUS_PLATFORMDOOR" << "STATUS_CABUNOCCUPIED";
                                        QString status = list1.at(lastStatus-1);
                                        qDebug() << status << "routeID:" << msgPkg.routeID << "deskID:" << msgPkg.destID
                                                 << "stationID:" << msgPkg.stationID;
                                    }
                                    //提交消息
                                    if(bChange)
                                    {
                                        SubmitMsg(&msgPkg);
                                    }

                                    //回复TIS
                                    sendToTis(Correct);
                                }
                                else
                                {
                                    //回复TIS
//                                    qDebug() << "bcc err" << (int)pkg->tail.hbcc << (int)pkg->tail.lbcc;
                                    sendToTis(BccError);
                                }
                            }


                            //移动缓冲标示
                            i = i+sizeof(tisNormalPkg);

                            continue;
                        }
                    }
                    else
                    {
                        buf.remove(0, i);//删除i前面所有,不包括i所指
                        return;
                    }

                    break;
                }
                case 0x31:
                {
                    if((buf.size()-i) >= sizeof(tisSelfTestPkg))
                    {
                       // tisSelfTestPkg* pkg= (tisSelfTestPkg*)(&buf[i]);
                        tisSelfTestPkg* pkg= (tisSelfTestPkg*)(buf.data()+i);
                        if(pkg->tail.etx == 0x03)
                        {
                            if(pkg->head.type == m_nTisSeq)
                            {
                                emit selfTest();
                            }

                            //移动缓冲标示
                            i = i+sizeof(tisSelfTestPkg);

                            continue;
                        }
                    }
                    else
                    {
                        buf.remove(0, i);//删除i前面所有,不包括i所指
                        return;
                    }

                    break;
                }
                case 0x32:
                {
                    if((buf.size()-i) >= sizeof(tisModifyProgPkg))
                    {
                        //tisModifyProgPkg* pkg= (tisModifyProgPkg*)(&buf[i]);
                        tisModifyProgPkg* pkg= (tisModifyProgPkg*)(buf.data()+i);
                        if(pkg->tail.etx == 0x03)
                        {
                            if(pkg->head.type == m_nTisSeq)
                            {
                                QByteArray bufCheck;
                                bufCheck.append((char*)pkg, sizeof(tisNormalPkg));
                                if(CheckBCC(bufCheck))
                                {
                                    sendToTis(Correct);
                                }
                                else
                                {
                                    sendToTis(BccError);
                                }
                            }
                            //移动缓冲标示
                            i = i+sizeof(tisModifyProgPkg);

                            continue;
                        }
                    }
                    else
                    {
                        buf.remove(0, i);//删除i前面所有,不包括i所指
                        return;
                    }

                    break;
                }
                default:
                {                    
                    QString msg = tr("TIS cmd err[");
                    for(int j = i; j < buf.size(); j++)
                    {
                        msg.append(QString("0x%1").arg(QString::number(((int)(*(buf.data()+i+j))&0xFF), 16)));
                        if (j != (buf.size()-1))
                            msg.append(", ");
                    }
                    msg.append("]\n");
                    logger()->warn(msg);

                    break;
                }
                }//end switch
            }
            else    //长度不够，将已处理的数据删，未处理的数据移到数组前
            {
               buf.remove(0, i);//删除i前面所有,不包括i所指
               return;
            }
        }

        i++;

    }//end while
    buf.clear();
}


void  NumToHex(unsigned char cIn, unsigned char szOut[2])
{
        if((cIn & 0x0F)<10)
        {
                szOut[0] = (cIn & 0x0F) + '0';
        }
        else
        {
                szOut[0] = (cIn & 0x0F)-10+'A';
        }

        if((cIn>>4)<10)
        {
                szOut[1] = (cIn>>4) + '0';
        }
        else
        {
                szOut[1] = (cIn>>4) - 10 + 'A';
        }
}

bool Tis::CheckBCC(QByteArray& buf)
{
    unsigned char sum = 0;
    for (int i = 0; i < buf.size()-2; i++)
    {
        if(i==0)
        {
            sum = buf.at(i);
        }
        else
        {
            sum ^= buf.at(i);
        }
    }

    unsigned char bcc[2] = {0};


    NumToHex(sum,bcc);
//    qDebug()<< "PIS:" << QString::number(bcc[0], 16)
//            << QString::number(bcc[1], 16)
//            << "tis:" << QString::number(((int)buf.at(buf.size()-1))&0xFF, 16)
//            << QString::number(((int)buf.at(buf.size()-1))&0xFF, 16);


    if(buf.at(buf.size()-1) == bcc[0]
       && buf.at(buf.size()-2) == bcc[1])
    {

        return true;
    }

    QString msg = tr("tis check bcc err");

    for(int i = 0; i < buf.size(); i++)
    {
        msg.append(QString(", 0x%1").arg(QString::number(((int)buf[i])&0xFF, 16)));
    }
    msg.append("\n");

    logger()->warn(msg);


    return false;
}

bool Tis::CreateBCC(QByteArray& buf, unsigned char bcc[2])
{
    if(bcc == NULL)
    {
        return false;
    }

    unsigned char sum = 0;
    for (int i = 0; i < buf.size(); i++)
    {
       if(i==0)
       {
           sum = buf.at(i);
       }
       else
       {
           sum ^= buf.at(i);
       }
    }

    NumToHex(sum, bcc);

    return true;
}


//内存由使用者释放
void Tis::SubmitMsg(tisToPisPkg *data)
{
    IMsg* tisMsg;
    int nLen = sizeof(tisToPisPkg);
    tisMsg = (IMsg*)malloc(sizeof(IMsg)+sizeof(char)*nLen);
    tisMsg->base.msgType = MSG_TIS;
    tisMsg->base.bodyLen = nLen;
    memcpy(tisMsg->body, data, nLen);

    try
    {
        emit msgArrive(tisMsg);
    }
    catch(...)
    {
        qDebug("error");
    }

    free(tisMsg);       //???在这里释放是否合理
}


//只针对同一时间只有一种状态发生变化的情况进行处理
uchar Tis::TranslateStatus(uchar status)
{
    uchar statusID = m_statusID;
    uchar change = status^m_status;
    if(change)
    {
        if(change & CABSTATUS)
        {
            if(status & CABSTATUS)
            {
                statusID = STATUS_CABOCCUPIED;
            }
        }
        else
        if(change & DOORSTATUS)
        {
            if(status & DOORSTATUS)
            {
                statusID = STATUS_DOOROPEN;
            }
            else
            {
                statusID = STATUS_DOORCLOSE;
            }
        }
        else
        if(change & TRAVELINGSTATUS)
        {
            if((status & TRAVELINGSTATUS) == 0)
            {
                statusID = STATUS_TRAVELING;
            }
        }
    }

    m_status = status;
    m_statusID = statusID;

    return statusID;
}


//只针对同一时间只有一种状态发生变化的情况进行处理
bool Tis::TranslateStatus(uchar tisStatus, uchar& myStatus, uchar& platSide)
{
    QString str = QString::number(tisStatus, 2);
    uchar statusID = m_statusID;
    uchar change = tisStatus^m_status;
    platSide = 0;

//    qDebug() << "tisStatus======>" << str;
    //首先是查询当前状态是否与上次不同，如果没有即不处理
    if(change)
    {
        if(change & CABSTATUS)
        {
//            qDebug() << "TranslateStatus >>>>>>>>>>>>>>> STATUS_CABOCCUPIED";
            if(tisStatus & CABSTATUS)           //CAB OCCUPIED 变化
            {
                statusID = STATUS_CABOCCUPIED;  //且被占用（即从 UNOCCUPIED－>OCCUPIED时才触发）
            } else {
                statusID = STATUS_CABUNOCCUPIED;
                m_isTrunAround = true;
            }
        }
        else
        if(change & DOORSTATUS)
        {
            if(tisStatus & DOORSTATUS)
            {
                statusID = STATUS_DOOROPEN;
            }
            else
            {
                statusID = STATUS_DOORCLOSE;
            }
        }
        else
        if(change & TRAVELINGSTATUS)
        {
            if((tisStatus & TRAVELINGSTATUS) == 0)
            {
                statusID = STATUS_TRAVELING;
            }
        }
        else
        if(change & PLATFORMSIDE)
        {
            if(tisStatus & PLATFORMSIDE)
            {
                uchar status = tisStatus >> 1;
                uchar sideValue = status & 0x03;
                statusID = STATUS_PLATFORMDOOR;
                platSide = sideValue;
            }
        }
    }
//    else
//    {
//        return false;
//    }

    //因为platFormSide信号在travling信号发过来时也是存在的，所以在travling过后就是platFormSide了
    if (lastStatus == STATUS_TRAVELING)
    {
        //后面会改变tisStatus的值，所以必须在此处赋值先
        m_status = tisStatus;

        tisStatus = tisStatus >> 1;
        uchar sideValue = tisStatus & 0x03;
        statusID = STATUS_PLATFORMDOOR;
        platSide = sideValue;

        myStatus = statusID;        //注意myStatus不能用值传递
        m_statusID = statusID;
        return true;
    }


    m_status = tisStatus;
    myStatus = statusID;        //注意myStatus不能用值传递
    m_statusID = statusID;

    return (change ? true : false);
}
